package org.testing.dbunit.extension;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.dbunit.assertion.DbUnitAssert;
import org.dbunit.assertion.FailureHandler;
import org.dbunit.dataset.Column;

public class AsserterWithComparators extends DbUnitAssert {
    private final Map<String, Comparator<Object>> comparators;
    private final Column[] columns;

    public AsserterWithComparators(Map<String, Comparator<Object>> comparators,
	    Set<Column> columns) {
	super();
	this.comparators = fixCaseSensitive(comparators);
	this.columns = columns.toArray(new Column[columns.size()]);
    }

    protected Map<String, Comparator<Object>> fixCaseSensitive(
	    Map<String, Comparator<Object>> comparators) {
	Map<String, Comparator<Object>> comparatorsWithUpperCaseKey = new HashMap<String, Comparator<Object>>();
	for (Entry<String, Comparator<Object>> entry : comparators.entrySet()) {
	    comparatorsWithUpperCaseKey.put(entry.getKey().toUpperCase(),
		    entry.getValue());
	}
	return comparatorsWithUpperCaseKey;
    }

    @Override
    protected boolean skipCompare(String columnName, Object expectedValue,
	    Object actualValue) {
	final Comparator<Object> comparator = comparators.get(columnName
		.toUpperCase());
	return (comparator != null)
		&& (comparator.compare(expectedValue, actualValue) == 0);
    }

    @Override
    protected FailureHandler getDefaultFailureHandler(
	    Column[] additionalColumnInfo) {
	final FailureHandler handler;
	if (additionalColumnInfo == null || additionalColumnInfo.length == 0) {
	    handler = super.getDefaultFailureHandler(columns);
	} else {
	    handler = super.getDefaultFailureHandler(concatenate(this.columns,
		    additionalColumnInfo));
	}
	return handler;
    }

    private static Column[] concatenate(Column[] c1, Column[] c2) {
	final List<Column> columns = new ArrayList<Column>(c1.length
		+ c2.length);
	columns.addAll(Arrays.asList(c1));
	columns.addAll(Arrays.asList(c2));
	return columns.toArray(new Column[columns.size()]);
    }
}